﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using subtitle_modifier.Entitys;
using log4net;


namespace subtitle_modifier
{
    public class SrtFile
    {
        protected static readonly ILog log = LogManager.GetLogger(typeof(SrtFile));
        private string MainLanguage;
        public FileInfo Info;
        private RecordList records;

        public RecordList Records
        {
            get { return records; }
            set { records = value; }
        }
        private TopLowerRepresentor _topLowerRepresentor;

        public TopLowerRepresentor topLowerRepresentor
        {
            get { return _topLowerRepresentor; }
            set { _topLowerRepresentor = value; }
        }

        public SrtFile(string FullPath)
        {
           
            Records = new RecordList();
            Info = new FileInfo(FullPath);
            Form1.Instance.addInfo(String.Format("Starting parsing file: {0}. ",Info.Name));
            Record CurrentRecord;
            string[] FileLines = File.ReadAllLines(FullPath, Encoding.Default);
            int i = 0;
            do
            {
               
                    CurrentRecord = new Record();
                    string[] times;
                    char[] delimiters;
                    string[] TempTime;

                    try
                    {
                    CurrentRecord.Id = Int32.Parse(FileLines[i]);
                   
                    i++;

                    times = Regex.Split(FileLines[i], "-*>");
                   
                    delimiters = new char[] { ':', ',' };
                    
                   TempTime = times[0].Split(delimiters);

                    CurrentRecord.StartShowingTime = new TimeSpan(0, Int32.Parse(TempTime[0]), Int32.Parse(TempTime[1]), Int32.Parse(TempTime[2]), Int32.Parse(TempTime[3]));
                    TempTime = times[1].Split(delimiters);
                    CurrentRecord.EndShowingTime = new TimeSpan(0, Int32.Parse(TempTime[0]), Int32.Parse(TempTime[1]), Int32.Parse(TempTime[2]), Int32.Parse(TempTime[3]));
                    i++;

                    while (i < FileLines.Length && !FileLines[i].Equals(""))
                    {
                        CurrentRecord.AddSentence(FileLines[i]);
                        i++;
                    }
                    i++;
                    Records.RecordsList.Add(CurrentRecord);
                }
                catch (Exception e)
                {

                    log.Error(e);
                }

            }
            while (i < FileLines.Length);
            MainLanguage = IdentifyFileanguage();

            topLowerRepresentorCreator();
            Form1.Instance.addInfo(String.Format("Finish  parsing file: {0}. ", Info.Name));

        }

        private void topLowerRepresentorCreator()
        {
            log.Info("creating topLowerRepresentor");
            int numberOfRecord = Records.RecordsList.Count;
            int cutFromSide = ((numberOfRecord * 30) / 100) / 2;//getting the 15% to cut from each side by index in the record list

           Record lower =Records.RecordsList[numberOfRecord - cutFromSide];
           Record top = Records.RecordsList[cutFromSide];
           topLowerRepresentor = new TopLowerRepresentor(top, lower); 
           log.Info("finish creat topLowerRepresentor ");
           log.Info(String.Format("lower record number after cuting 30%: {0}/{2} top record number after cuting 30%: {1}/{2}", topLowerRepresentor.Lower.Id, topLowerRepresentor.Top.Id, numberOfRecord));
         
               
        }

        //This func. is too damn slow!!
        public void TranslateRecords(string fromCulture, string toCulture)
        {
            MainLanguage = toCulture;
            foreach (Record r in Records.RecordsList)
            {
                for (int i = 0; i < r.GetSentencesCount(); i++)
                {
                    r.SetSentenceAt(i, Translation.TranslateGoogle((string)(r.GetSentenceAt(i)), fromCulture, toCulture));
                }
            }
        }

        private string IdentifyFileanguage()
        {
            int count = 0;
            string lang="";
            string CurrentLanguage = "";
            for (int i = 0; i < 30; i++ )
            {
                Random random = new Random();
                int num = random.Next(Records.RecordsList.Count);
                CurrentLanguage=Translation.WhatLanguage(((Record)Records.RecordsList[num]).GetSentenceAt(0));
                if (CurrentLanguage.Equals(lang))
                {
                    count++;
                    if ( count > 5 )
                    {
                        break;
                    }
                }
                else
                {
                    lang = CurrentLanguage;
                    count = 0;
                }
            }
            return lang;
        }

        public void WriteToNewSrtFile()
        {
            FileInfo NewSrtFile = new FileInfo(String.Format("{0}\\{1}_{2}.Srt",Info.Directory,Info.Name,MainLanguage));
            StreamWriter SW = new StreamWriter(NewSrtFile.FullName, false, Encoding.Default);
            foreach (Record r in Records.RecordsList)
            {
                SW.Write(r);
            }
            SW.Write("\r");
            SW.Close();
        }
        public void AddTimeToRecords(TimeSpan TimeToAdd)
        {
            foreach (Record r in Records.RecordsList)
            {
                r.AddTme(TimeToAdd);
            }
            if (TimeToAdd >= new TimeSpan(0, 0, 0))
            {
                log.Info(TimeToAdd.Duration()+" was added to " + this.Info.Name);
            }
            else 
            {
                log.Info(TimeToAdd.Duration() + " was decreased from " + this.Info.Name);
            }
        }

        //returns the records No. in case that text is displayed on given time. else returns -1*(first bigger record No.)
        public int OnWhichRecordDoesTextdisplayed(TimeSpan Time)
        {
            int LowIndex = 0;
            int HighIndex = Records.RecordsList.Count-1;
            int AvgIndex = 0;
            int Direction = 0;
            while (LowIndex <= HighIndex)
            { 
                AvgIndex = (LowIndex + HighIndex)/2;
                Direction = ((Record)(Records.RecordsList[AvgIndex])).ContainsTime(Time);
                switch (Direction)
                {
                    case -1:
                        {
                            HighIndex = AvgIndex-1;
                        }
                        break;
                    case 0:
                        {
                            return ((Record)(Records.RecordsList[AvgIndex])).Id;
                        }
                        break;
                    case 1:
                        {
                            LowIndex = AvgIndex + 1;
                        }
                        break;
                    default:
                        break;
                }
            }
            if ((-1) == Direction)
            {
                return -1 * (((Record)(Records.RecordsList[AvgIndex])).Id);
            }
            else 
            {
                return -1 * (((Record)(Records.RecordsList[AvgIndex])).Id + 1);
            }
        }

        public Diff GetDiffFromRecord(Record ExternalRecord)
        {
            Diff ans;
            try
            {
                int TimesTheSentenceWasFound = 0;
                double FinalQuality = 0;
                double CurrentQuality = 0;
                int StartRecord = topLowerRepresentor.Top.Id;
                TimeSpan StartTime = ExternalRecord.StartShowingTime - (new TimeSpan(0, 3, 0));//from XML
                TimeSpan Diff = new TimeSpan();
                if (StartTime > topLowerRepresentor.Top.StartShowingTime)
                {
                    StartRecord = OnWhichRecordDoesTextdisplayed(StartTime);
                    StartRecord = Math.Abs(StartRecord);
                }
                int EndRecord = topLowerRepresentor.Lower.Id;
                TimeSpan EndTime = ExternalRecord.EndShowingTime + (new TimeSpan(0, 3, 0));//from XML
                if (EndTime < topLowerRepresentor.Lower.StartShowingTime)
                {
                    EndRecord = OnWhichRecordDoesTextdisplayed(EndTime);
                    EndRecord = Math.Abs(EndRecord);
                }

                //string SentenceToFind = ExternalRecord.GetSentenceAt(0);
                string SentenceToFind = ExternalRecord.AppendSentences().Replace('.', ',');
                SentenceToFind = SentenceToFind + ".";
                SentenceToFind = Translation.TranslateGoogle(SentenceToFind, "", MainLanguage);
                for (int i = StartRecord; i <= EndRecord; i++)
                {
                    string SentenceToCompareWith = Records.RecordsList[i].AppendSentences().Replace('.', ',');
                    CurrentQuality = GeneralFunctions.SimilarSentences(SentenceToFind, SentenceToCompareWith);

                    if (CurrentQuality > 80)//from XML
                    {
                        TimesTheSentenceWasFound++;
                        Diff = ExternalRecord.StartShowingTime - Records.RecordsList[i].StartShowingTime;
                        FinalQuality = CurrentQuality;
                        
                    }
                }
                if (1 != TimesTheSentenceWasFound)
                {
                    FinalQuality = -1;
                }
                ans = new Diff(Diff, FinalQuality);
            }
            catch (Exception e)
            {

                log.Error(e);
                return null;
            }
            
            return ans;
            
        }

        public TimeSpan GetDiffFromFilePhase1(SrtFile ExternalFile)
        {
            Diff CurrentCheck = null;
            List<double> doubleList = new List<double>();
            Record RandomRecordFormExternal;
           
            try
            {
                Form1.Instance.addInfo("0% complited");
                while (doubleList.Count() <= 10)//from XML
                {
                    RandomRecordFormExternal = ExternalFile.GetRandomRecord();
                   
                    if (!RandomRecordFormExternal.Formated && GeneralFunctions.WordCount(RandomRecordFormExternal.AppendSentences().Replace('.', ',')) > 5) //from XML
                    {
                      
                        CurrentCheck = GetDiffFromRecord(RandomRecordFormExternal);
                     
                        if (CurrentCheck.Quality > 80)//from XML
                        {
                            Form1.Instance.replaceLastLine(String.Format("{0}% complited", (100 * doubleList.Count() / 10)));
                            doubleList.Add(CurrentCheck.DiffTime.TotalMilliseconds);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                log.Error(e);
            }
            doubleList.Sort();
            double avg = doubleList.Average();
            double std = GeneralFunctions.getStandardDeviation(doubleList);
            while (std > 100)//from XML
            {
                int index = Math.Abs(doubleList[0] - avg) > Math.Abs(doubleList[doubleList.Count - 1] - avg) ? 0 : doubleList.Count - 1;
                doubleList.RemoveAt(index);
                avg = doubleList.Average();
                std = GeneralFunctions.getStandardDeviation(doubleList);
            }
            return new TimeSpan(0, 0, 0, 0, (int)avg);            
        }

        protected Record GetRandomRecord()
        {
            Random random = new Random();
            int RandomID = random.Next(topLowerRepresentor.Top.Id, topLowerRepresentor.Lower.Id);
            return Records.RecordsList[RandomID-1];
        }
    }
}